﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows;
using System.Security.Permissions;
using System.Windows.Media;
using Bixas.Tangibilis.Input;

namespace Bixas.Tangibilis.Input
{
    public class TouchCursorDevice : InputDevice
    {
        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public void PreProcessInput(object sender, PreProcessInputEventArgs e)
        {
            RawTouchCursorInputEventArgs args = e.StagingItem.Input as RawTouchCursorInputEventArgs;
            // On ne filtre que les messages de type TouchCursorEventArgs
            if (args != null)
            {

                // Si la fenêtre principal n'est pas active
                // on désactive l'interception des messages
                if (args.CurrentWindow == null)
                {
                    args.Handled = true;
                }

                if (!args.Handled)
                {
                    if (args.Operation != RawTouchCursorOperation.Delete)
                    {

                        //bool translated = false;
                        //Point a = new Point((double)args.Cursor.Left, (double)args.Cursor.Top);
                        //Point data = (Point)e.StagingItem.GetData(this._tagRootPoint);
                        //Point point2 = InputElementHack.TranslatePoint(a, args.CurrentWindow, (DependencyObject)args.Cursor.CursorOver, out translated);
                        //IInputElement enabledHit = args.Cursor.CursorOver;


                        IInputElement enabledHit = args.Cursor.CursorOver;
                        IInputElement originalHit = (args.Cursor.RawCursorOver != null) ? ((IInputElement)args.Cursor.RawCursorOver.Target) : null;

                        enabledHit = (IInputElement)HitTest(args);
                        if (args.Cursor.CaptureMode == CaptureMode.Element)
                        {
                            if (enabledHit != args.Cursor.Captured)
                                enabledHit = args.Cursor.Captured;

                        }

                        if (args.Cursor.Captured != enabledHit)
                        {
                            UpdateCapture((DependencyObject)enabledHit, e);
                        }
                    }
                    else
                    {
                       // UpdateCapture(null, e);
                    }
                }

            }

            /*if (!(e.StagingItem.Input is TouchCursorEventArgs) || e.StagingItem.Input.Handled)
            {
                if (e.StagingItem.Input is TouchCursorEventArgs)
                {
                    TouchCursorEventArgs input = (TouchCursorEventArgs)e.StagingItem.Input;
                    if ((input.RoutedEvent != null) && input.IsPreviewEvent)
                    {
                        input.IsReady = true;
                    }
                }
            }
            else
            {
                TouchCursorEventArgs args = (TouchCursorEventArgs)e.StagingItem.Input;
                 if (args.IsReady)
                {
                    if (!args.CurrentWindow.IsActive)
                    {
                        e.StagingItem.Input.Handled = true;
                    }
                }
                else
                {
                    if ((args.CurrentWindow == null))
                    {
                        if (args.RoutedEvent != null)
                        {
                            e.StagingItem.Input.Handled = true;
                        }
                    }
                    else
                    {
                        bool flag = false;
                        DependencyObject depObj = null;
                        if (args.RoutedEvent == null)
                        {
                            depObj = HitTest(args);
                            UpdateCapture(depObj, e);
                            flag = true;
                        }
                        else
                        {
                            depObj = (DependencyObject)args.Cursor.Captured;
                        }
                        if (depObj != null)
                        {
                            if (flag)
                            {
                                RaisePreviewCursorEvents(depObj, e);
                            }
                            else
                            {
                                RaiseCursorEvents(depObj, e);
                            }
                        }
                    }
                }
            }*/
        }

        [EnvironmentPermission(SecurityAction.LinkDemand, Unrestricted = true)]
        public void PostProcessInput(object sender, ProcessInputEventArgs e)
        {
            
            RawTouchCursorInputEventArgs args = e.StagingItem.Input as RawTouchCursorInputEventArgs;
            // On ne filtre que les messages de type TouchCursorEventArgs
            if (args != null)
            {
                bool flag = false;

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewDownEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorDownEvent;
                    flag = true;
                }

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewUpEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorUpEvent;
                    flag = true;
                }

                if ((args.RoutedEvent == TouchCursorEvents.TouchCursorPreviewMoveEvent) && !e.StagingItem.Input.Handled)
                {
                    args.RoutedEvent = TouchCursorEvents.TouchCursorMoveEvent;
                    flag = true;
                }
                if (flag)
                {
                    args.Source = args.Cursor.Captured;
                    args.IsReady = true;
                    e.PushInput(args, e.StagingItem);
                }
                if (!args.IsPreviewEvent)
                {
                    if (args.Operation == RawTouchCursorOperation.Add)
                    {
                        double left = args.Cursor.Left;
                        double top = args.Cursor.Top;
                        args.Cursor.SetPosition((int)left, (int)top);
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewDownEvent;
                    }
                    else if (args.Operation == RawTouchCursorOperation.Delete)
                    {
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewUpEvent;
                    }
                    else if (args.Operation == RawTouchCursorOperation.Update)
                    {
                        double left = args.Cursor.Left;
                        double top = args.Cursor.Top;
                        args.Cursor.SetPosition((int)left, (int)top);
                        args.RoutedEvent = TouchCursorEvents.TouchCursorPreviewMoveEvent;
                    }
                    if (args.RoutedEvent != null)
                    {
                        args.Source = args.Cursor.Captured;
                        args.IsPreviewEvent = true;
                        e.PushInput(args, e.StagingItem);
                    }
                }
            }

            
          /*  TouchCursorEventArgs input = (TouchCursorEventArgs)e.StagingItem.Input;
            if (input.Operation == CursorInputOperation.Add)
            {
                input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewDownEvent;
            }
            else if (input.Operation == CursorInputOperation.Delete)
            {
                input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewUpEvent;
            }
            else if (input.Operation == CursorInputOperation.Update)
            {
                input.RoutedEvent = TouchCursorEvents.TouchCursorPreviewMoveEvent;
            }
            if (input.RoutedEvent != null)
            {
                input.Source = depObj;
                input.IsPreviewEvent = true;
                e.PushInput(input, e.StagingItem);
            }
            */
        }

        private static DependencyObject HitTest(RawTouchCursorInputEventArgs args)
        {
            DependencyObject reference = null;
            if ((PresentationSource.FromVisual(args.CurrentWindow) != null))
            {
                Visual rootVisual = PresentationSource.FromVisual(args.CurrentWindow).RootVisual;
                //double left = ((MultiPointMouseDevice)args.DeviceInfo.DeviceVisual).Left;
                //double top = ((MultiPointMouseDevice)args.DeviceInfo.DeviceVisual).Top;

                double left =  args.Cursor.Left;
                double top =  args.Cursor.Top;
                Point point = new Point(left, top);
                HitTestResult result = VisualTreeHelper.HitTest(rootVisual, point);
                if (result != null)
                {
                    reference = result.VisualHit;
                }
                while (reference != null)
                {
                    reference = VisualTreeHelper.GetParent(reference);
                    if (reference is ITouchCursorEvent)
                    {
                        return reference;
                    }
                }
            }
            return reference;
        }

        private static void UpdateCapture(DependencyObject depObj, PreProcessInputEventArgs e)
        {
            RawTouchCursorInputEventArgs input = (RawTouchCursorInputEventArgs)e.StagingItem.Input;
            if ((depObj == null) && (input.Cursor.Captured != null))
            {
                input.RoutedEvent = TouchCursorEvents.TouchCursorLeaveEvent;
                input.Source = input.Cursor.Captured;
                input.Cursor.Captured = null;
                InputManager.Current.ProcessInput(input);
                e.StagingItem.Input.Handled = true;
            }
            if (depObj != null)
            {
                if ((input.Cursor.Captured != null) && (input.Cursor.Captured != depObj))
                {
                    input.RoutedEvent = TouchCursorEvents.TouchCursorLeaveEvent;
                    input.Source = input.Cursor.Captured;
                    //input.Cursor.Captured.RaiseEvent(input);
                    input.Cursor.Captured = null;
                    InputManager.Current.ProcessInput(input);
                }
                if (input.Cursor.Captured == null)
                {
                    input.Cursor.Captured = (IInputElement)depObj; 
                    input.RoutedEvent = TouchCursorEvents.TouchCursorEnterEvent;
                    //input.Source = depObj;
                    //element3.RaiseEvent(input);
                    input.Source = input.Cursor.Captured;
                    InputManager.Current.ProcessInput(input);
                    
                }
            }
        }

        public override PresentationSource ActiveSource
        {
            get { throw new NotImplementedException(); }
        }

        public override IInputElement Target
        {
            get { throw new NotImplementedException(); }
        }
    }
}
